package org.javia.arity;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ComplexTest {

	Complex complex1;
	Complex complex2;
	final Complex infinite= new Complex(Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY);
	final Complex nan= new Complex(Double.NaN,Double.NaN);
	final Complex zero= new Complex(0,0);
	
	
	@Before
	public void setUp() throws Exception {
		complex1=new Complex(1.2345, 3.6543);
		complex2= new Complex(-1,-2);
	}

	@After
	public void tearDown() throws Exception {
	}

	
	@Test
	public void testComplexDoubleDouble() {
		Complex complex3=new Complex(complex1.re,complex1.im);
		assertEquals("",complex3,complex1);
	}

	@Test
	public void testComplexComplex() {
		assertEquals(complex1, new Complex(complex1));
	}

	@Test
	public void testSetDoubleDouble() {
		complex1.set(complex2.re, complex2.im);
		assertEquals(complex2, complex1);
	}

	@Test
	public void testSetComplex() {
		complex1.set(complex2);
		assertEquals(complex2,complex1);
	}

	@Test
	public void testToString() {
		assertEquals("(1.2345, 3.6543)",complex1.toString());
		complex1.im=0;
		assertEquals("1.2345",complex1.toString());
	}

	@Test
	public void testAsReal() {
		assertEquals(Double.NaN,complex1.asReal(),0.0001);
		complex1.set(complex1.re, 0);
		assertEquals(complex1.re,complex1.asReal(),0.0001);
		
	}

	@Test
	public void testConjugate() {
		Complex complex3=complex1.conjugate();		
		assertEquals("(1.2345, -3.6543)",complex3.toString());
	}

	@Test
	public void testNegate() {
		Complex complex3=complex1.negate();
		assertEquals("(-1.2345, -3.6543)",complex3.toString());
	}

	@Test
	public void testIsInfinite() {
		Boolean b=complex1.isInfinite();
		assertTrue(infinite.isInfinite());
		assertFalse(b);
	}

	@Test
	public void testIsFinite() {
		Boolean b=complex1.isFinite();
		
		assertTrue(b);
		assertFalse(infinite.isFinite());
	}

	@Test
	public void testIsNaN() {
		Boolean b=complex1.isNaN();
		
		assertFalse(b);
		assertTrue(nan.isNaN());
	}

	@Test
	public void testEqualsComplex() {
		assertTrue(complex1.equals(complex1));
		assertFalse(complex1.equals(complex2));
		assertFalse(complex1.equals(null));
	}

	@Test
	public void testArg() {
		Double d=complex1.arg();
		assertEquals(1.2450121477594285,d,0.0001);
	}

	@Test
	public void testAbs() {
		Double d=complex1.abs();
		assertEquals(3.8571879316413917,d,0.0001);
		Complex com= new Complex(0,1);
		assertEquals(1,com.abs(),0.0001);
	}

	@Test
	public void testAbs2() {
		Double d=complex1.abs2();
		assertEquals(14.87789874,d,0.0001);
	}

	@Test
	public void testAdd() {
		Complex complex3=complex1.add(complex1);
		assertEquals("(2.469, 7.3086)",complex3.toString());
		complex3= new Complex(0,0);
		Complex complex4=complex3.add(new Complex(0,0));
		assertEquals("0.0",complex4.toString());
	}

	@Test
	public void testSub() {
		Complex complex3=complex1.sub(complex2);
		assertEquals("(2.2344999999999997, 5.6543)", complex3.toString());
		
		complex3= new Complex(0,0);
		Complex complex4=complex3.sub(new Complex(0,0));
		assertEquals("0.0",complex4.toString());
	}

	@Test
	public void testMulDouble() {
		Complex complex3=complex1.mul(3.0);
		assertEquals("(3.7035, 10.962900000000001)", complex3.toString());
		
		complex3= new Complex(0,0);
		Complex complex4=complex3.mul(new Complex(0,0));
		assertEquals("0.0",complex4.toString());
	}

	@Test
	public void testMulComplex() {
		Complex complex3=complex1.mul(complex1);
		assertEquals("(-11.829918240000001, 9.022466699999999)", complex3.toString());
		Complex c4=complex3.mul(infinite);
		assertEquals("(NaN, Infinity)",c4.toString());
		
		Complex c5= infinite.mul(complex1);
		assertEquals("(NaN, NaN)",c5.toString());
		
		
		Complex c6= new Complex(Double.POSITIVE_INFINITY,0);
		Complex c7= new Complex(0,Double.POSITIVE_INFINITY);
		
		assertEquals(c7,c6.mul(c7));
		
		Complex c8=new Complex();
		c8.re=Double.NEGATIVE_INFINITY;
		assertEquals(c8,c7.mul(c6));
		
		
		
	}

	@Test
	public void testDiv() {
		Complex complex3=complex1.div(complex2);
		assertEquals("(-1.7086200000000002, -0.23706000000000005)",complex3.toString());
	}

	@Test
	public void testSqrt() {
		Complex c=complex1.sqrt();
		assertEquals("(1.595570106833509, 1.145139277913694)",c.toString());
		
		
		Complex c1= new Complex(1,0);
		assertEquals(new Complex(1,0),c1.sqrt());
		assertEquals(new Complex(0,1),c1.set(-1,0).sqrt());
		
		Complex c2= new Complex(-1,1);
		Complex c3= c2.sqrt();
		assertEquals(0.455089,c3.re,0.0001);
		assertEquals(1.0986,c3.im,0.0001);
		
		c2= new Complex(-2,-2);
		c3= c2.sqrt();
		assertEquals(0.64359,c3.re,0.0001);
		assertEquals(-1.55377,c3.im,0.0001);
	}

	@Test
	public void testMod() {
		Complex c=complex1.mod(complex2);
		assertEquals("(-0.7655000000000001, -0.3456999999999999)",c.toString());
		Complex c2=new Complex(2,0);
		assertEquals(c2,c2.mod(c2));
	}

	@Test
	public void testGcd() {
		Complex c=complex1.gcd(complex2);
		assertEquals("(4.440892098500626E-16, -2.220446049250313E-16)",c.toString());
		Complex c2=new Complex(2,0);
		assertEquals(c2,c2.gcd(c2));
	}

	@Test
	public void testLog() {
		Complex c=complex1.log();
		assertEquals("(1.3499384028618369, 1.2450121477594285)",c.toString());
		Complex c2=new Complex(1,0);
		assertEquals(new Complex(0,0),c2.log());
	}

	@Test
	public void testExp() {
		Complex c=complex1.exp();
		assertEquals("(-2.9947728320099865, -1.6858131565221297)",c.toString());
		Complex c2=new Complex(1,0);
		assertEquals(Math.E,c2.exp().re,0.001);
	}

	@Test
	public void testSquare() {
		Complex c=complex1.square();
		assertEquals("(-11.829918240000001, 9.022466699999999)",c.toString());
	}

	@Test
	public void testPow() {
		Complex c=complex1.pow(complex2);
		assertEquals("(-2.171221539422362, 2.2503682077953027)",c.toString());
		
		Complex c2=new Complex(1,0);
		assertEquals(new Complex(1,0),c2.pow(new Complex(0,0)));
		assertEquals(new Complex(1,0),c2.pow(new Complex(1,1)));
		assertEquals(new Complex(1,0),c2.pow(new Complex(1,0)));
		c2.im=1;
		assertEquals(new Complex(0,2),c2.pow(new Complex(2,0)));
		assertEquals(new Complex(1,1),c2.pow(new Complex(0.5,0)));
		assertEquals(new Complex(-4,0),c2.pow(new Complex(4,0)));
	}

	@Test
	public void testLgamma() {
		Complex c=complex1.lgamma();
		assertEquals("(-2.5167854874701225, 3.4177582165315123)",c.toString());
	}

	@Test
	public void testFactorial() {
		Complex c=complex1.factorial();
		assertEquals("(-0.07766007293392238, -0.022009437866152)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(new Complex(1,0),c1.factorial());
	}

	@Test
	public void testSin() {
		Complex c=complex1.sin();
		assertEquals("(18.25019146125073, 6.371274206252453)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0.84147,c1.sin().re,0.0001);
	}

	@Test
	public void testSinh() {
		Complex c=complex1.sinh();
		assertEquals("(-1.3706034775682598, -0.914275045129295)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(1.1752,c1.sinh().re,0.0001);
	}

	@Test
	public void testCos() {
		Complex c=complex1.cos();
		assertEquals("(6.379814299442617, -18.2257615439362)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0.540302,c1.cos().re,0.0001);
	}

	@Test
	public void testCosh() {
		Complex c=complex1.cosh();
		assertEquals("(-1.6241693544417268, -0.7715381113928347)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(1.54308,c1.cosh().re,0.0001);
	}

	@Test
	public void testTan() {
		Complex c=complex1.tan();
		assertEquals("(8.354100292606563E-4, 1.0010479757686894)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(1.55741,c1.tan().re,0.0001);
	}

	@Test
	public void testTanh() {
		Complex c=complex1.tanh();
		assertEquals("(0.9066846442259223, 0.1322111431958106)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0.76159,c1.tanh().re,0.0001);
	}

	@Test
	public void testAsin() {
		Complex c=complex1.asin();
		assertEquals("(0.31598814084138077, 2.056329200848436)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(1.57079,c1.asin().re,0.0001);
	}

	@Test
	public void testAcos() {
		Complex c=complex1.acos();
		assertEquals("(1.2548081859535163, -2.0563292008484377)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0,c1.acos().re,0.0001);
	}

	@Test
	public void testAtan() {
		Complex c=complex1.atan();
		assertEquals("(1.4827630223073724, 0.24884606411349156)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0.785399,c1.atan().re,0.0001);
	}

	@Test
	public void testAsinh() {
		Complex c=complex1.asinh();
		assertEquals("(2.0296191401924006, 1.2343984946177964)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0.881373,c1.asinh().re,0.0001);
	}

	@Test
	public void testAcosh() {
		Complex c=complex1.acosh();
		assertEquals("(2.0563292008484377, 1.2548081859535163)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(0,c1.acosh().re,0.0001);
	}

	@Test
	public void testAtanh() {
		Complex c=complex1.atanh();
		assertEquals("(2.826644472557674, 1.3284320340378346)",c.toString());
		Complex c1= new Complex(1,0);
		assertEquals(Double.POSITIVE_INFINITY,c1.atanh().re,0.0001);
	}

	@Test
	public void testCombinations() {
		Complex c=complex1.combinations(complex1);
		assertEquals("(-0.007561334700804227, -0.010076090914630846)",c.toString());
		assertEquals(-0.00756,complex1.combinations(new Complex(1,0)).re,0.0001);
	}

	@Test
	public void testPermutations() {
		Complex c=complex1.permutations(complex1);
		assertEquals("(-0.004878551868171987, 3.264868621993604E-4)",c.toString());
	}
	
	@Test
	public void testHashCode(){
		assertEquals(-517793992,complex1.hashCode());
	}
	

}
